package owg.util.opengl;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;

import javax.imageio.ImageIO;

import com.jogamp.opengl.util.GLBuffers;


public class TextureLib
{
	private static HashMap<String,Tex> textures = new HashMap<String,Tex>();
	/**
	 * Loads all textures we can find in the given directory
	 */
	/**Loads images from directory path, returns references to loaded textures*/
	public static ArrayList<Tex> loadDir(String dirName, boolean forcePOTS)
	{
		ArrayList<Tex> loaded= new ArrayList<Tex>();
		
		File dir = new File(dirName);
		System.out.print("Load graphics dir: "+dirName+" ");
		if(dir.isDirectory()) 
		{
			String filenames[] = dir.list();
			for (String fname : filenames)
			{
				final int lastDot = fname.lastIndexOf('.');
				
				//Only attempt to load files that have an extension.
				if(lastDot != -1) 
				{
					final String extension = fname.substring(lastDot+1, fname.length()).toLowerCase(Locale.ENGLISH);
					//Only attempt to load known image files.
					if (	!extension.equals("png")  && 
						!extension.equals("gif")  &&
						!extension.equals("jpg")  &&
						!extension.equals("jpeg") &&
						!extension.equals("bmp"))
						continue;
					
					final String nameWithoutExtension = fname.substring(0, lastDot);
					int lastUnderscore = nameWithoutExtension.lastIndexOf('_');
					
					
					int numXFrames = 1;
					int numYFrames = 1;
					String simpleName = nameWithoutExtension;
					//If name ends with underscore and number, then assume it is an image strip with that number of frames.
					//If name ends two sets of underscore and number, then assume it is a grid: _xframes_yframes.
					
					//Get the last number
					int parseIntR = -1;
					if(lastUnderscore != -1) 
					{
						String frameCountString = nameWithoutExtension.substring(lastUnderscore+1, nameWithoutExtension.length());
						try 
						{
							parseIntR = Integer.parseInt(frameCountString);
							simpleName = nameWithoutExtension.substring(0, lastUnderscore);
						}
						catch (NumberFormatException e) {}
					}
					if(parseIntR != -1) 
					{
						lastUnderscore = simpleName.lastIndexOf('_');
						//Get the second-to-last number
						int parseIntL = -1;
						if(lastUnderscore != -1) 
						{
							String frameCountString = simpleName.substring(lastUnderscore+1, simpleName.length());
							
							try 
							{
								parseIntL = Integer.parseInt(frameCountString);
								simpleName = simpleName.substring(0, lastUnderscore);
							}
							catch (NumberFormatException e) {}
						}
						//If we found two numbers
						if(parseIntL != -1) 
						{
							numXFrames = parseIntL;
							numYFrames = parseIntR;
						}
						else 
						{//One number
							numXFrames = parseIntR;
						}
					}
					//Flags for mipmap and mag filter
					boolean premul = false, mipmap = false, bilinearMag = false;
					
					if (simpleName.endsWith("_pre"))
					{
						simpleName = simpleName.substring(0, simpleName.length() - 4);
						premul = true;
					}
					if (simpleName.endsWith("_mip"))
					{
						simpleName = simpleName.substring(0, simpleName.length() - 4);
						mipmap = true;
					}
					if (simpleName.endsWith("_mag"))
					{
						simpleName = simpleName.substring(0, simpleName.length() - 4);
						bilinearMag = true;
					}
					
					loaded.add(loadTexture(dirName+"/"+fname, numXFrames, numYFrames, premul, mipmap, forcePOTS, bilinearMag, simpleName));
				}
			}
			System.out.println("Done");
		}
		
		return loaded;
	}
	/**
	 * Loads the texture in the given file. The file name is relative to the game directory. Returns reference to loaded texture.
	 * @param simpleName 
	 * @param numYFrames 
	 * @param numXFrames 
	 */
	public static Tex loadTexture(String fname, int numXFrames, int numYFrames, boolean premul, boolean mipmap, boolean forcePOTS, boolean bilinearMag, String simpleName)
	{
		// Load texture.
		try {
			InputStream stream = new FileInputStream(fname);
			
			BufferedImage bi = ImageIO.read(stream);
			int imWidth = bi.getWidth();
			int imHeight = bi.getHeight();
			
			int frameWidth = imWidth/numXFrames;
			int frameHeight = imHeight/numYFrames;
			System.out.print(simpleName+' ');
			if(bi.getType()!=BufferedImage.TYPE_4BYTE_ABGR)
			{
				BufferedImage old = bi;
				bi = new BufferedImage(old.getWidth(),old.getHeight(),BufferedImage.TYPE_4BYTE_ABGR);
				Graphics g = bi.createGraphics();
				g.drawImage(old, 0, 0, null);
				g.dispose();
				old.flush();
				System.out.print("->RGBA8 ");
			}
			final float xMult, yMult;
			final int texWidth, texHeight;
			
			if(mipmap) 
			{
				texWidth = frameWidth;
				texHeight = frameHeight;
				xMult = 1.0f;
				yMult = 1.0f;
				System.out.print("->mipmaps ");	
				
			}
			else if(forcePOTS)
			{
				texWidth = GLBuffers.getNextPowerOf2(frameWidth);
				texHeight = GLBuffers.getNextPowerOf2(frameHeight);
				xMult = (float)frameWidth/texWidth;
				yMult = (float)frameHeight/texHeight;
			}
			else
			{
				texWidth = frameWidth;
				texHeight = frameHeight;
				xMult = 1.0f;
				yMult = 1.0f;
			}
			
			byte[][] data = new byte[numXFrames*numYFrames][];
			
			int currentImage = 0;
			for(int y = 0; y < numYFrames; y++)
			{
				for(int x = 0; x < numXFrames; x++)
				{
					data[currentImage] = new byte[bi.getWidth()*bi.getHeight()*4];
					byte[] bytes = data[currentImage];
					bi.getRaster().getDataElements(x*frameWidth, y*frameHeight, frameWidth, frameHeight, bytes);
					
					if(premul)
					{
						for(int i = 0; i<bytes.length; i += 4)
						{
							int a = bytes[i+3]&0xFF;
							bytes[i  ] = (byte)(((bytes[i  ]&0xFF)*a)/0xFF);
							bytes[i+1] = (byte)(((bytes[i+1]&0xFF)*a)/0xFF);
							bytes[i+2] = (byte)(((bytes[i+2]&0xFF)*a)/0xFF);
						}
					}
					
					currentImage++;
				}
			}
			
			Tex tex = new Tex(simpleName, data, frameWidth, frameHeight, xMult, yMult, mipmap, bilinearMag);
			textures.put(simpleName, tex);
			return tex;
		}
		catch (IOException exc) 
		{
			System.err.println("Loading texture "+simpleName+" failed miserably");
			exc.printStackTrace();
		}
		
		return null;
	}
	
	/**
	 * Find the Texture array associated with the given name.
	 * */
	public static Tex tex(String textureName)
	{
		Tex t = textures.get(textureName);
		if(t==null)
			System.err.println("Warning: Texture "+textureName+" not found!");
		return t;
	}
	
	public static void removeTexture(Tex tex){
		textures.remove(tex);
	}
	
}
